package com.gs.coursera.algorithms.core.graph;

/**
 * An Edge with 2 vertices. Can have weight and direction. The direction is
 * always from startVertex to endVertex.
 * 
 * @author Sabuj
 *
 * @param <T>
 * @param <W>
 */
public class Edge<T, W extends Comparable<W>> implements Comparable<Edge<T, W>>{

	private final Vertex<T, W> startVertex;
	private final Vertex<T, W> endVertex;
	private W weight;
	private boolean isDirected = false;
	private boolean treeEdge = false;
	private boolean backEdge = false;
	private boolean crossEdge = false;

	public Edge(Vertex<T, W> v1, Vertex<T, W> v2) {
		this(v1, v2, null);
	}

	public Edge(Vertex<T, W> v1, Vertex<T, W> v2, W w) {
		this.startVertex = v1;
		this.endVertex = v2;
		this.weight = w;
		startVertex.addAdjacentEdge(this);
	}

	public W getWeight() {
		return weight;
	}

	public void setWeight(W weight) {
		this.weight = weight;
	}

	public boolean isDirected() {
		return isDirected;
	}

	public void setDirected(boolean isDirected) {
		this.isDirected = isDirected;
	}

	public Vertex<T, W> getStartVertex() {
		return startVertex;
	}

	public Vertex<T, W> getEndVertex() {
		return endVertex;
	}

	public boolean isLabled() {
		return (treeEdge || backEdge || crossEdge);
	}

	public boolean isTreeEdge() {
		return treeEdge;
	}

	public void setTreeEdge(boolean treeEdge) {
		this.treeEdge = treeEdge;
	}

	public boolean isBackEdge() {
		return backEdge;
	}

	public void setBackEdge(boolean backEdge) {
		this.backEdge = backEdge;
	}

	public boolean isCrossEdge() {
		return crossEdge;
	}

	public void setCrossEdge(boolean crossEdge) {
		this.crossEdge = crossEdge;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result
				+ ((endVertex == null) ? 0 : endVertex.hashCode());
		result = prime * result
				+ ((startVertex == null) ? 0 : startVertex.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj) {
			return true;
		}
		if (obj == null) {
			return false;
		}
		if (!(obj instanceof Edge)) {
			return false;
		}
		Edge other = (Edge) obj;
		if (endVertex == null) {
			if (other.endVertex != null) {
				return false;
			}
		} else if (!endVertex.equals(other.endVertex)) {
			return false;
		}
		if (startVertex == null) {
			if (other.startVertex != null) {
				return false;
			}
		} else if (!startVertex.equals(other.startVertex)) {
			return false;
		}
		return true;
	}

	public int compareTo(Edge<T, W> o) {
		return this.weight.compareTo(o.weight);
	}

	@Override
	public String toString() {
		return String
				.format("Edge [s=%s, v=%s, w=%s]",
						startVertex, endVertex, weight);
	}

}
